package cn.edu.hit.joinsystem.controller;

import cn.edu.hit.CacheManager;
import cn.edu.hit.core.db.DBReadHelper;
import cn.edu.hit.core.db.DataConnection;
import cn.edu.hit.core.db.DataConnectionLoader;
import cn.edu.hit.core.db.DataReader;
import cn.edu.hit.kg.data.GraphData;
import cn.edu.hit.kg.data.Node;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

@RestController
public class SelflearningController {
    @Autowired
    HttpServletRequest request;

    static Logger logger = LoggerFactory.getLogger(SelflearningController.class);

    public static final CacheManager cacheManager = CacheManager.getInstance();

    static GraphData graphData = GraphData.getInstance();
    static DataConnection connection = DataConnectionLoader.getInstance();
    static DataReader reader = connection.getReader();
    static DBReadHelper dbHelper = new DBReadHelper(reader);

    /**
     * 用来获取已结束的故障
     *
     */
    @CrossOrigin
    @RequestMapping(method = RequestMethod.GET, value = "endfaults", produces = "application/json;charset=UTF-8")
    public JSONArray getEndFaults() {
        Set<String> keys = null;
        try{
            cacheManager.getJedis().keys("end_fault:" + "*");
        }catch (Exception e){
            cacheManager.getJedis().close();
        }finally {
            keys = cacheManager.getJedis().keys("end_fault:" + "*");
        }
        logger.info(keys.toString());
        JSONArray jarr = new JSONArray();
        for (String key : keys) {
            JSONObject fault = new JSONObject();
            String reportId = key.substring(10);
            long size = 0L;
            try{
                cacheManager.getJedis().llen(key);
            }catch (Exception e){
                cacheManager.getJedis().close();
            }finally {
                size = cacheManager.getJedis().llen(key);
            }
            JSONArray jsonArray = new JSONArray();
            for (long i = 0; i < size; i++) {
                String json = null;
                try{
                    json = cacheManager.getJedis().lindex(key, i);
                }catch (Exception e){
                    cacheManager.getJedis().close();
                }finally {
                    json = cacheManager.getJedis().lindex(key, i);
                }
                JSONObject jobj = JSONObject.fromObject(json);
                String keys2 = "feature_frequency:" + jobj.getString("machineNumber") + ":" + jobj.getInt("feature_id");
                if (cacheManager.getJedis().exists(keys2)) {
                    String json2 = cacheManager.getJedis().get(keys2);
                    JSONObject jobj2 = JSONObject.fromObject(json2);
                    jobj.put("quantum", jobj2.get("quantum"));
                    jobj.put("frequency", jobj2.getJSONObject("frequency").get(jobj.getString("fault_id")));
                }
                jobj.put("properties", graphData.getById(jobj.getInt("feature_id")).asMap());
                jsonArray.add(jobj);
                if (i == 0) {
                    fault.put("properties", graphData.getById(jobj.getInt("fault_id")).asMap());
                    JSONObject reason_pr = this.loadReasonFreq(jobj.getString("machineNumber"), jobj.getInt("fault_id"));
                    List<Map> reasons = graphData.getAllSubNodes(jobj.getInt("fault_id"))
                            .filter(node -> node.hasLabel("Reason"))
                            .map(r -> {
                                JSONObject reason = JSONObject.fromObject(r.asMap());
                                reason.put("id", r.id());
                                return reason;
                            }).collect(Collectors.toList());
                    fault.put("reasons", reasons);
                    fault.put("reasons_probability", reason_pr);
                }
            }
            fault.put("features", jsonArray);
            fault.put("reportId", reportId);
            jarr.add(fault);
        }
        return jarr;
    }

    /**
     * 用来获取实时发生的故障
     *
     */
    @CrossOrigin
    @RequestMapping(method = RequestMethod.GET, value = "nowfaults", produces = "application/json;charset=UTF-8")
    public JSONArray getRealtimeFaults() {
        Set<String> keys = null;
        try{
            keys = cacheManager.getJedis().keys("fault_feature:*");
        }catch (Exception e){
            cacheManager.getJedis().close();
        }finally {
            keys = cacheManager.getJedis().keys("fault_feature:*");
        }

        JSONArray jarr = new JSONArray();
        for (String key : keys) {
            JSONObject fault = new JSONObject();
            long size = 0L;

            try {
                cacheManager.getJedis().llen(key);
            }catch(Exception e) {
                cacheManager.getJedis().close();
            }finally {
                size = cacheManager.getJedis().llen(key);
            }

            JSONArray jsonArray = new JSONArray();
            for (long i = 0; i < size; i++) {
                String json = cacheManager.getJedis().lindex(key, i);
                JSONObject jobj = JSONObject.fromObject(json);
                String keys2 = "feature_frequency:" + jobj.getString("machineNumber") + ":" + jobj.getInt("feature_id");
                if (cacheManager.getJedis().exists(keys2)) {
                    String json2 = cacheManager.getJedis().get(keys2);
                    JSONObject jobj2 = JSONObject.fromObject(json2);
                    jobj.put("quantum", jobj2.get("quantum"));
                    jobj.put("frequency", jobj2.getJSONObject("frequency").get(jobj.getString("fault_id")));
                }
                Node featurenode = graphData.getById(jobj.getInt("feature_id"));
                JSONObject properties = JSONObject.fromObject(featurenode.asMap());
                properties.put("entityType", featurenode.labels().iterator().next());
                jobj.put("properties", graphData.getById(jobj.getInt("feature_id")).asMap());

                jsonArray.add(jobj);
                if (i == 0) {
                    fault.put("properties", graphData.getById(jobj.getInt("fault_id")).asMap());
                    JSONObject reason_pr = this.loadReasonFreq(jobj.getString("machineNumber"), jobj.getInt("fault_id"));
                    List<Map> reasons = graphData.getAllSubNodes(jobj.getInt("fault_id"))
                            .filter(node -> node.hasLabel("Reason"))
                            .map(r -> {
                                JSONObject reason = JSONObject.fromObject(r.asMap());
                                reason.put("id", r.id());
                                return reason;
                            }).collect(Collectors.toList());

                    fault.put("reasons", reasons);
                    fault.put("reasons_probability", reason_pr);
                }
            }
            //此处应该添加一个last_timestamp   让ui界面显示故障发生时间
            fault.put("features", jsonArray);
            jarr.add(fault);
        }
        return jarr;
    }

    /**
     * 用于获取故障列表
     * @return
     */



    public JSONObject loadFeature(@PathVariable("machineNumber") String machineNumber, @PathVariable("id") long id, @PathVariable("faultId") long faultId) {
        String freqKey = "feature_frequency:" + machineNumber + ':' + id;
        JSONObject freq;
        if (cacheManager.getJedis().exists(freqKey)) {
            freq = JSONObject.fromObject(cacheManager.getJedis().get(freqKey));
        } else {
//            GraphData graphData = GraphData.getInstance();
            freq = new JSONObject();
            Node feature = graphData.getById(id);

//            if (fault.asMap().containsKey("quantum")) {
//                freq.put("quantum", "" + fault.asMap().get("quantum"));
//            } else {
//                freq.put("quantum", "100");
//            }

            if (feature.asMap().get("quantum") == null) {
                freq.put("quantum", 100);
            } else {
                freq.put("quantum", feature.asMap().get("quantum"));
            }
            if (feature.asMap().get("frequency") == null) {
                JSONObject fault = new JSONObject();
                fault.put("" + faultId, 80);
                freq.put("frequency", fault);
            } else {
                JSONObject fault = new JSONObject();
                fault.put("" + faultId, JSONObject.fromObject(feature.asMap().get("frequency")).get(""+faultId));
                freq.put("frequency", fault);
            }
        }
        return freq;
    }

    public JSONObject loadReasonFreq(@PathVariable("machineNumber") String machineNumber, @PathVariable("id") long fault_id) {
        String freqKey = "fault_reason:" + machineNumber + ":" + fault_id;
        JSONObject freq;
        if (cacheManager.getJedis().exists(freqKey)) {
            freq = JSONObject.fromObject(cacheManager.getJedis().get(freqKey));
        } else {
            freq = new JSONObject();
            Node fault = graphData.getById(fault_id);
            freq.put("quantum", fault.asMap().getOrDefault("quantum", 100));
            if (fault.asMap().containsKey("frequency")) {
                freq.put("frequency", fault.asMap().get("frequency"));
            } else {
                freq.put("frequency", graphData.getAllSubNodes(fault_id)
                        .filter(node -> StreamSupport.stream(node.labels().spliterator(), false)
                                .anyMatch(x -> x.equals("Reason")))
                        .collect(Collectors.toMap(x -> "" + x.id(), x -> Double.parseDouble(x.asMap().get("probability").toString()) * 100)));
            }
        }
        return freq;
    }

    @CrossOrigin
    @RequestMapping(method = RequestMethod.POST, value = "increaseTrain", produces = "application/json;charset=UTF-8")
    public JSONObject train(@RequestBody String body) {

        JSONObject jsonObject = JSONObject.fromObject(body);
        String machineNumber = jsonObject.getString("machine");
        String reportId = jsonObject.getString("reportId");
        JSONArray features = jsonObject.getJSONArray("features");
        JSONArray reasons = jsonObject.getJSONArray("reasons");

        String line = cacheManager.getJedis().lpop("end_fault:" + reportId);
        JSONObject faultJson = JSONObject.fromObject(line);
        long faultId = faultJson.getLong("fault_id");
        features.forEach(feature -> {
            long featureId = Long.parseLong((String) feature);
            JSONObject Featurefreq = loadFeature(machineNumber, featureId, faultId);
            Featurefreq.put("quantum", Featurefreq.optInt("quantum") + 1);
            Featurefreq.getJSONObject("frequency").put("" + faultId, Featurefreq.getJSONObject("frequency").optInt("" + faultId) + 1);
            String freqKey = "feature_frequency:" + machineNumber + ":" + featureId;
            String res = Featurefreq.toString();
            cacheManager.getJedis().set(freqKey, res);
        });

        JSONObject reasonFreq = loadReasonFreq(machineNumber, faultId);

        reasons.forEach(reason -> {
            long reasonId = ((Integer) reason).longValue();
            reasonFreq.put("quantum", reasonFreq.optInt("quantum") + 1);
            reasonFreq.getJSONObject("frequency").put("" + reasonId, reasonFreq.getJSONObject("frequency").optInt("" + reasonId) + 1);
        });

        cacheManager.getJedis().set("fault_reason:" + machineNumber + ":" + faultId, reasonFreq.toString());
//        cacheManager.getJedis().del("end_fault:" + reportId);
        JSONObject result = new JSONObject();
        result.put("result", true);
        logger.info("已增加置信度reportId:{}", reportId);
        return result;
    }

    @CrossOrigin
    @RequestMapping(method = RequestMethod.POST, value = "decreaseTrain", produces = "application/json;charset=UTF-8")
    public JSONObject train2(@RequestBody String body) {
        JSONObject jsonObject = JSONObject.fromObject(body);
        String machineNumber = jsonObject.getString("machine");
        String reportId = jsonObject.getString("reportId");
        JSONArray features = jsonObject.getJSONArray("features");
        JSONArray reasons = jsonObject.getJSONArray("reasons");

        String line = cacheManager.getJedis().lpop("end_fault:" + reportId);
        JSONObject faultJson = JSONObject.fromObject(line);
        long faultId = faultJson.getLong("fault_id");
        features.forEach(feature -> {
            long featureId = Long.parseLong((String) feature);
            JSONObject Featurefreq = loadFeature(machineNumber, featureId, faultId);
            Featurefreq.put("quantum", Featurefreq.optInt("quantum") + 1);
            Featurefreq.getJSONObject("frequency").put("" + faultId, Featurefreq.getJSONObject("frequency").optInt("" + faultId) - 1);
            String freqKey = "feature_frequency:" + machineNumber + ":" + featureId;
            String res = Featurefreq.toString();
            cacheManager.getJedis().set(freqKey, res);
        });
        JSONObject result = new JSONObject();
        result.put("result", true);
        logger.info("已减小置信度reportId:{}", reportId);
        return result;
    }

    @CrossOrigin
    @RequestMapping(method = RequestMethod.GET, value = "clear", produces = "application/json;charset=UTF-8")
    public JSONObject clear(@RequestBody String body) {
        JSONObject bodyObject = JSONObject.fromObject(body);
        String reportId = bodyObject.getString("reportId");
        cacheManager.getJedis().del("end_fault:" + reportId);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("result", true);
        logger.info("已删除reportId：{}", reportId);
        return jsonObject;
    }

    @CrossOrigin
    @RequestMapping("/flushdb")
    public String flushall(){
        return cacheManager.getJedis().flushAll();
    }
}



